/*
 * @Description: 互斥线程锁
 * @Author: iwonmo
 * @Date: 2021-06-29 14:42:20
 */
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "lock.h"

/**
 * 获取系统对齐大小
 * 
 * @Author: iwonmo
 * @Date: 2021-06-30 14:33:39
 * @Param: 
 * @Return: 
 */
size_t GetUnixSystemAlignmentSize()
{
    struct
    {
        int MxInt;
    } x;

    struct
    {
        int MxInt;
        char MxChar;
    } y;

    return sizeof(y) - sizeof(x);
}

/**
 * 对齐大小
 * 
 * @Author: iwonmo
 * @Date: 2021-06-30 14:33:58
 * @Param: 
 * @Return: 
 * @param {size_t} Size
 */
size_t AlignUnixSize(size_t Size)
{
    size_t AlignSize = GetUnixSystemAlignmentSize();

    if (Size % AlignSize)
        Size += AlignSize - (Size % AlignSize);

    return Size;
}
BOOL handleName(char *Name, size_t *StartPos, size_t Size, char **ResultMem)
{
    char Name2[255], Nums[50];
    char *Prefix = "/io_mutex_";
    size_t x, x2 = 0, y = strlen(Prefix), z = 0;
    *StartPos = (Name != NULL ? AlignUnixSize(1) + AlignUnixSize(sizeof(pthread_mutex_t)) + AlignUnixSize(sizeof(uint32_t)) : 0);
    Size += *StartPos;
    Size = sync_AlignUnixSize(Size);
    memset(Name2, 0, sizeof(Name2));
    for (x = 0; x < y; x++)
    {
        Name2[x2] = (char)(((unsigned int)(unsigned char)Name2[x2]) * 37 + ((unsigned int)(unsigned char)Prefix[x]));
        x2++;

        if (x2 == sizeof(Name2) - 1)
        {
            x2 = 1;
            z++;
        }
    }

    y = strlen(Name);
    for (x = 0; x < y; x++)
    {
        Name2[x2] = (char)(((unsigned int)(unsigned char)Name2[x2]) * 37 + ((unsigned int)(unsigned char)Name[x]));
        x2++;

        if (x2 == sizeof(Name2) - 1)
        {
            x2 = 1;
            z++;
        }
    }

    /* 尝试创建命名的共享内存对象。 */
    int fp = shm_open(Name2, O_RDWR | O_CREAT | O_EXCL, 0666);
    if (fp == -1)
        fp = shm_open(Name2, O_RDWR, 0666);
    if (fp > -1)
    {
        if (ftruncate(fp, Size) < 0)
        {
            close(fp);
            shm_unlink(Name2);
            return FALSE;
        }
        *ResultMem = (char *)mmap(NULL, Size, PROT_READ | PROT_WRITE, MAP_SHARED, fp, 0);
        if (ResultMem == MAP_FAILED)
        {
            return FALSE;
        }
        close(fp);
    }
    return TRUE;
}

/**
 * 初始化互斥线程锁的属性由于是静态属性所以是全局的
 * 
 * @Author: iwonmo
 * @Date: 2021-06-30 09:52:41
 * @Param: 
 * @Return: 
 */
int io_mutex_init()
{
    if (io_lock_ready == TRUE)
    {
        return FALSE;
    }
    if (pthread_mutexattr_init(&io_lock_attr) == SUCCESS)
    {
        io_lock_ready = TRUE;
        pthread_mutexattr_setpshared(&io_lock_attr, PTHREAD_PROCESS_SHARED);
        // pthread_mutexattr_settype(&io_lock_attr, PTHREAD_MUTEX_RECURSIVE);

        pthread_condattr_init(&condAttr);
        pthread_condattr_setpshared(&condAttr, PTHREAD_PROCESS_SHARED);
        return TRUE;
    }

    return FALSE;
}

/**
 * 释放互斥线程锁的资源
 * 
 * @Author: iwonmo
 * @Date: 2021-06-30 09:57:33
 * @Param: 
 * @Return: 
 */
void io_mutex_cleanup()
{
    if (io_lock_ready == TRUE)
        return;

    io_lock_ready = FALSE;

    pthread_mutexattr_destroy(&io_lock_attr);
}
size_t GetUnixSemaphoreSize()
{
    return AlignUnixSize(sizeof(pthread_mutex_t)) + AlignUnixSize(sizeof(uint32_t)) + AlignUnixSize(sizeof(uint32_t)) + AlignUnixSize(sizeof(pthread_cond_t));
}

char *getMem(char *name)
{
    size_t Pos, TempSize;
    TempSize = GetUnixSemaphoreSize();
    char *MxMem;
    handleName(name, &Pos, TempSize, &MxMem); //保证获取到的地址是同一个
    return MxMem + Pos;
}

pthread_cond_t *getCond(char *Mem)
{
    Mem += AlignUnixSize(sizeof(pthread_mutex_t));
    Mem += AlignUnixSize(2);
    return (pthread_cond_t *)(Mem);
}

int io_mutex_lock(pthread_mutex_t *mutex, pthread_cond_t *cond)
{
    pthread_mutex_init(mutex, &io_lock_attr);
    pthread_cond_init(cond, &condAttr);
    pthread_mutex_lock(mutex);
}

int io_mutex_unlock(pthread_mutex_t *mutex, pthread_cond_t *cond)
{
    pthread_mutex_unlock(mutex);
    pthread_mutex_destroy(mutex);
    pthread_cond_destroy(cond);
}

int io_mutex_wait(pthread_mutex_t *mutex, pthread_cond_t *cond, int m)
{

    struct timespec abstime;
    struct timeval now;
    long timeout_ms = m; // wait ms
    gettimeofday(&now, NULL);
    long nsec = now.tv_usec * 1000 + (timeout_ms % 1000) * 1000000;
    abstime.tv_sec = now.tv_sec + nsec / 1000000000 + timeout_ms / 1000;
    abstime.tv_nsec = nsec % 1000000000;

    pthread_cond_timedwait(cond, mutex, &abstime);
}